﻿using NDF.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace NDF.Reflection
{
    /// <summary>
    /// 提供对 程序集(<see cref="System.Reflection.Assembly"/>) 操作的常用工具方法。
    /// </summary>
    public static class AssemblyHelper
    {
        /// <summary>
        /// 获取包含当前指定的代码的程序集。
        /// </summary>
        /// <returns>返回一个程序集对象，该对象包含当前指定的代码。</returns>
        public static Assembly GetCurrentAssembly()
        {
            return Assembly.GetExecutingAssembly();
        }

        /// <summary>
        /// 获取已加载到此应用程序域的执行上下文中的程序集。
        /// </summary>
        /// <returns>此应用程序域中的程序集的数组。</returns>
        public static Assembly[] GetAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        /// <summary>
        /// 获取已加载到指定应用程序域作用范围内执行上下文中的程序集。
        /// </summary>
        /// <param name="domain">指定的应用程序域作用范围。</param>
        /// <returns>已加载到指定应用程序域作用范围内执行上下文中程序集的数组。</returns>
        public static Assembly[] GetAssemblies(AssemblyDomain domain)
        {
            return domain == AssemblyDomain.Current ? GetCurrentAssembly().ToEnumerable().ToArray() : GetAssemblies();
        }





        /// <summary>
        /// 获取已加载到此应用程序域执行上下文所有程序集中定义的所有类型<see cref="System.Type"/>集合所构成的一个数组。
        /// </summary>
        /// <returns>已加载到此应用程序域执行上下文所有程序集中定义的所有类型<see cref="System.Type"/>集合所构成的一个数组。</returns>
        public static Type[] GetTypes()
        {
            return GetTypes(AssemblyDomain.AppDomain);
        }

        /// <summary>
        /// 获取已加载到指定应用程序域作用范围内执行上下文所有程序集中定义的所有类型<see cref="System.Type"/>集合所构成的一个数组。
        /// </summary>
        /// <param name="domain">指定的应用程序域作用范围。</param>
        /// <returns>已加载到指定应用程序域作用范围内执行上下文所有程序集中定义的所有类型<see cref="System.Type"/>集合所构成的一个数组。</returns>
        public static Type[] GetTypes(AssemblyDomain domain)
        {
            return GetAssemblies(domain).SelectMany(assembly => GetTypes(assembly)).Distinct().ToArray();
        }



        /// <summary>
        /// 获取已加载到此应用程序域执行上下文所有程序集中定义的所有公共类型<see cref="System.Type"/>集合(这些公共类型在程序集外可见)所构成的一个数组。
        /// </summary>
        /// <returns>已加载到此应用程序域执行上下文所有程序集中定义的所有公共类型<see cref="System.Type"/>集合(这些公共类型在程序集外可见)所构成的一个数组。</returns>
        public static Type[] GetPublicTypes()
        {
            return GetPublicTypes(AssemblyDomain.AppDomain);
        }

        /// <summary>
        /// 获取已加载到指定应用程序域作用范围内执行上下文所有程序集中定义的所有公共类型<see cref="System.Type"/>集合(这些公共类型在程序集外可见)所构成的一个数组。
        /// </summary>
        /// <param name="domain">指定的应用程序域作用范围。</param>
        /// <returns>已加载到指定应用程序域作用范围内执行上下文所有程序集中定义的所有公共类型<see cref="System.Type"/>集合(这些公共类型在程序集外可见)所构成的一个数组。</returns>
        public static Type[] GetPublicTypes(AssemblyDomain domain)
        {
            return GetAssemblies(domain).SelectMany(assembly => assembly.ExportedTypes).Distinct().ToArray();
        }






        /// <summary>
        /// 获取已加载到此应用程序域执行上下文所有程序集中定义的所有命名空间集合所构成的一个数组。
        /// </summary>
        /// <returns>已加载到此应用程序域执行上下文所有程序集中定义的所有命名空间集合所构成的一个数组。</returns>
        public static string[] GetNamespaces()
        {
            return GetNamespaces(AssemblyDomain.AppDomain);
        }

        /// <summary>
        /// 获取已加载到指定应用程序域作用范围内执行上下中所有程序集中定义的所有命名空间集合所构成的一个数组。
        /// </summary>
        /// <param name="domain">指定的应用程序域作用范围。</param>
        /// <returns>已加载到指定应用程序域作用范围内执行上下中所有程序集中定义的所有命名空间集合所构成的一个数组。</returns>
        public static string[] GetNamespaces(AssemblyDomain domain)
        {
            return GetTypes(domain).Select(t => t.Namespace).Distinct().ToArray();
        }

        /// <summary>
        /// 获取当前应用程序集中已定义的所有命名空间集合所构成的一个数组。
        /// </summary>
        /// <param name="assembly">应用程序集。</param>
        /// <returns>当前应用程序集中已定义的所有命名空间集合所构成的一个数组。</returns>
        public static string[] GetNamespaces(this Assembly assembly)
        {
            return GetTypes(assembly).Select(t => t.Namespace).Distinct().ToArray();
        }



        /// <summary>
        /// 获取程序集中定义的类型。同 <seealso cref="Assembly.GetTypes"/>；
        /// 但在 <seealso cref="Assembly.GetTypes"/> 基础上屏蔽了 <see cref="System.Reflection.ReflectionTypeLoadException"/> 异常。
        /// </summary>
        /// <param name="assembly">应用程序集。</param>
        /// <returns>一个数组，包含此程序集中定义的所有类型。</returns>
        public static Type[] GetTypes(Assembly assembly)
        {
            return assembly.GetTypes();
            //Type[] types = null;
            //try
            //{
            //    types = assembly.GetTypes();
            //}
            //catch
            //{
            //    types = assembly.ExportedTypes.ToArray();
            //}
            //return types;
        }
    }
}
